<?php
/**
 * appRain v 0.1.x
 *
 * LICENSE
 *
 * This source file is subject to the MIT license that is bundled
 * with this package in the file LICENSE.txt.
 * It is also available through the world-wide-web at this URL:
 * http://www.opensource.org/licenses/mit-license.php
 * If you did not receive a copy of the license and are unable to
 * obtain it through the world-wide-web, please send an email
 * to license@apprain.com so we can send you a copy immediately.
 *
 * @copyright  Copyright (c) 2010 appRain, Team. (http://www.apprain.com)
 * @license    http://www.opensource.org/licenses/mit-license.php MIT license
 *
 * HELP
 *
 * Official Website
 * http://www.apprain.com/
 *
 * Download Link
 * http://www.apprain.com/download
 *
 * Documents Link
 * http ://www.apprain.com/docs
 */

class Component_Appstore_Helpers_Data extends appRain_Base_Objects
{
    const _minitem = 0;
    const _itemremovelimit = 0;
    const STATUS_PENDING = 'Pending';
    const STATUS_PROCESSING = 'Processing';
    const STATUS_COMPLETE = 'Complete';
    const STATUS_PAID = 'Paid';


    public  $enablepaymentprocessor = true;
    private $itemtotal = null;

    /**
     * Get Payment status in Array
     */
    public function getPaymentStatusList()
    {
        return Array(
            self::STATUS_PENDING=>self::STATUS_PENDING,
            self::STATUS_PAID=>self::STATUS_PAID
        );
    }

    /**
     * Get Delivery stats in Array
     */
    public function getDeliveryStatusList()
    {
        return Array(
            self::STATUS_PENDING=>self::STATUS_PENDING,
            self::STATUS_PROCESSING=>self::STATUS_PROCESSING,
            self::STATUS_COMPLETE=>self::STATUS_COMPLETE
        );
    }

    /**
     * Add Item
     */
    public function quickAdd($pid=null, $qty=null)
    {
        $this->cleartotalItem();

        if(!isset($pid) || !isset($qty)){
            throw new AppException($this->__("System error, Please try after a few moment."));
            return ;
        }

        $cartInfo = $this->getCartInfo();

        if($qty == self::_itemremovelimit) unset($cartInfo[$pid]);
        else $cartInfo[$pid] = (string) $qty;

        App::Module('Session')->write('appcart',$cartInfo);

        return $this;
    }

    /**
     *  Remove item from cart
     */
    public function removeItem($id=null)
    {
        $this->cleartotalItem();
        $cartInfo = $this->getCartInfo();

        if(isset($cartInfo[$id])) unset($cartInfo[$id]);

        App::Module('Session')->write('appcart',$cartInfo);
    }

    /**
     * Clear total item
     */
    public function cleartotalItem()
    {
        $this->itemtotal = null;
    }

    /**
     * Clear Cart from Session
     */
    public function clearcart()
    {
        $this->cleartotalItem();
        App::Module('Session')->delete('appcart');
        App::Module("Session")->delete("appOrderId");
    }

    /**
     * Get cart infor by product id
     */
    public function getCartInfoByProductId($id=null)
    {
        $cartInfo = App::Module('Session')->read('appcart');
        return isset($cartInfo[$id]) ? $cartInfo[$id] : self::_minitem;
    }

    /**
     * Get Cart Info
     */
    public function getCartInfo($pid = NULL)
    {
        $cartInfo = App::Module('Session')->read('appcart');

        if(isset($pid)){
            return isset($cartInfo[$pid]) ? $cartInfo[$pid] : null;
        }
        else{
            return empty($cartInfo) ? array() : $cartInfo;
        }
    }

    /**
     * Get Total Item info
     */
    public function getCartTotalItem()
    {
        if(!isset($this->itemtotal)){
            $this->itemtotal = 0;
            foreach($this->getCartInfo() as $item){
                $this->itemtotal += $item;
            }
        }
        return $this->itemtotal;
    }

    /**
     * Simple validation
     */
    public function isToCheckout()
    {
        return ($this->getCartTotalItem() > 0) ? true : false;
    }

    /**
     * Render Order Information
     */
    public function renderShoppingCart()
    {
        $currency = App::Helper('Config')->siteInfo('currency');

        $gandtotal = 0;
        $tqty = 0;
        $DataGrid = App::Module('DataGrid');
        foreach($this->getCartInfo() as $pid=> $qty){
            $tmp = Array();
            $product = App::InformationSet()->findById($pid);
            $tmp['title'] = $product['title'];
            $tmp['thumb'] = App::Helper('Html')->imgDTag(App::Helper('Config')->basedir("/uploads/filemanager/{$product['imagethumb']}"));
            $tmp['shortdesc'] = trim(strip_tags($product['shortdesc']));
            $tmp['qty'] = $qty;
            $tmp['price'] = "{$qty}x{$product['price']}";
            $tmp['subtotal'] = "{$currency}" . ($qty * $product['price']);
            $gandtotal += ($qty * $product['price']);
            $tqty += $qty;

            $DataGrid->addRow(
                App::Helper('Html')->linkTag(App::Helper("Config")->baseurl("/checkout/removeitem/{$pid}"),App::Helper('Html')->imgTag(App::Helper('Config')->baseurl('/images/admin/remove.gif'))),
                $tmp['thumb'],
                $tmp['title'],
                $tmp['shortdesc'],
                $tmp['qty'],
                $tmp['price'],
                $tmp['subtotal']
              );
        }

        $DataGrid->setHeader(Array("","","Name","Description","Quantity","Price","Sub Total"))
             ->setFooter(Array("","","&nbsp;","&nbsp;","{$tqty}","&nbsp;","{$currency}{$gandtotal}"))
             ->Render();
    }

    /**
     * Create HTML View of an Invoice
     */
    public function getInvoice($orderid=NULL)
    {
        if(!isset($orderid)){
            $orderid = $this->getOrderId();
        }

        $currency = App::Helper('Config')->siteInfo('currency');

        $items = App::Model('Item')->findAllByOrderid($orderid);

        $gandtotal = 0;
        $tqty = 0;
        $DataGrid = App::Module('DataGrid');
        foreach($items['data'] as $val){
            $pid = $val['productid'];
            $qty = $val['qty'];

            $tmp = Array();
            $product = App::InformationSet()->findById($pid);

            $tmp['title'] = $product['title'];
            $tmp['thumb'] = App::Helper('Html')->imgDTag(App::Helper('Config')->basedir("/uploads/filemanager/{$product['imagethumb']}"));
            $tmp['shortdesc'] = trim(strip_tags($product['shortdesc']));
            $tmp['qty'] = $qty;
            $tmp['price'] = "{$qty} x {$product['price']}";
            $tmp['subtotal'] = "{$currency} " . ($qty * $product['price']);
            $gandtotal += ($qty * $product['price']);
            $tqty += $qty;

            $DataGrid->addRow(
                $tmp['thumb'],
                $tmp['title'],
                $tmp['shortdesc'],
                $tmp['qty'],
                $tmp['price'],
                $tmp['subtotal']
            );
        }

        return  $DataGrid->setHeader(Array("","Name","Description","Quantity","Item Price","Sub Total"))
            ->setFooter(Array("","","","{$tqty} (Total Qty)","&nbsp;","{$currency} {$gandtotal} (Total)"))
            ->Render(true,Array("border"=>'1','width'=>'100%','cellspacing'=>'3','cellpadding'=>"3","bordercolor"=>"#E4802A"));
    }

    /**
     * Check if order exists in Database
     */
    public function isOrderExistsInDB($id)
    {
        $data = App::Model('Order')->findById($id);

        return !empty($data);
    }

    /**
     * Retrive order id
     */
    public function getOrderId()
    {
        $orderid = App::Module("Session")->Read("appOrderId");

        return (isset($orderid) && $this->isOrderExistsInDB($orderid)) ? $orderid : null;
    }

    /**
     * Register order id in Session
     */
    public function register($id=null)
    {
        if($this->getOrderId() === null){
            App::Module("Session")->Write("appOrderId",$id);
        }

    }

    /**
     * Move first instance in database
     */
    private function moveOrderInstanceToDB()
    {
        $obj = App::Model('Order')
            ->setId($this->getOrderId())
            ->setOrderdate(App::Helper('Date')->getDate())
            ->Save();

        if($obj->getErrorInfo()){

            echo App::Module("Cryptography")->jsonEncode(array( "_status" =>"Error", "_message"=>$this->__('Invalid Order Post data')));
            exit;
        }
        else {
            $this->Register($obj->getId());
        }

        return $this;
    }

    /**
     * Move Items in Database
     */
    private function moveItemsToDB()
    {
        $cartinfo = $this->getCartInfo();
        $orderid = $this->getOrderId();

        $itemsindb = App::Model('Item')->findAllByOrderId($orderid);

        $clonecartinfo = $cartinfo;
        if(!empty($itemsindb['data'])){
            foreach($itemsindb['data'] as $item){
                if(in_array($item['productid'],array_keys($clonecartinfo))){
                    $this->updateItemByPid($item['productid'],$item['id']);
                    if(isset($clonecartinfo[$item['productid']]))unset($clonecartinfo[$item['productid']]);
                }
                else{
                    App::Model('Item')->DeleteById($item['id']);
                }
            }
        }

        if(!empty($clonecartinfo)){
            foreach($clonecartinfo as $pid => $qty){
                $this->updateItemByPid($pid);
            }
        }

        return $this;
    }

    /**
     * Update Item Information
     */
    private function updateItemByPid($pid=null,$itemid=null)
    {
        $product = App::InformationSet()->findById($pid);

        $_pdo=App::Model('Item')
            ->setId($itemid)
            ->setOrderid($this->getOrderId())
            ->setProductid($pid)
            ->setDated(App::Helper('Date')->getDate('Y-m-d H:i:s'))
            ->setTitle($product['title'])
            ->setUnitprice($product['price'])
            ->setQty($this->getCartInfo($pid))
            ->setTotalprice($product['price'] * $this->getCartInfo($pid))
            ->setProductdata(serialize($product))
            ->setStatus(self::STATUS_PENDING)
            ->Save();
    }

    /**
     * Calculate total Qty
     */
    public function totalQty($orderid=null)
    {
        if(!isset($orderid)){
            $orderid = $this->getOrderId();
        }
        $data = App::Model('Item')
            ->find(
                "orderid={$orderid}",
                null,
                "sum(qty) as total"
            );

        return $data['total'];
    }

    /**
     * Calculate total Cost
     */
    public function totalCost($orderid=null)
    {
        if(!isset($orderid)){
            $orderid = $this->getOrderId();
        }

        $data = App::Model('Item')
            ->find(
                "orderid={$orderid}",
                null,
                "sum(totalprice) as total"
            );

        return $data['total'];
    }

    /**
     * Get Payment name from it's class
     */
    public function paymentMethodToStatusName($method)
    {
        try{
            return App::Component('appStore')->Helper("Pgateway_common")->getObject($method)->getStatusName();
        }
        catch(Exception $e){
            return $method;
        }

    }

    /**
     * Update order data completely
     */
    public function completeOrderUpdate()
    {
        $orderid = $this->getOrderId();
        $shippingadd = $this->getShippingAddress();
        $billingadd = $this->getBillingAddress();

        $method = $this->paymentMethodToStatusName($this->getPaymentMethod());

        if(!isset($orderid)){
            throw new AppException($this->__("Order Data is not formated"));
        }
        else{
            App::Model('Order')
               ->setId($orderid)
               ->setShippingaddress(serialize($shippingadd))
               ->setBillingaddress(serialize($billingadd))
               ->setPaymenttype($method)
               ->setQty($this->totalQty())
               ->setTotalcost($this->totalCost())
               ->Save();
        }

    }

    /**
     * Change the order status
     * bydefault the status is set to "Paid" for payment success
     */
    public function ChnageOrderStatus($orderid=NULL,$status=null,$isnotified=true)
    {
        if(!isset($orderid)) $orderid = $this->getOrderId();

        $Payment = App::Component('appStore')->Helper("Pgateway_common")->getObject($this->getPaymentmethod());

        if(!isset($status)) $status =$Payment->paymentStatus();

        App::Model('Order')
            ->setId($orderid)
           ->setPaymentType($this->getPaymentType())
           ->setPaymentstatus($status)
           ->setDeliverystatus($Payment->shippingStatus())
           ->Save();
        if($isnotified)
        {
            $this->sendOrderMail($orderid,$status);
        }

        return $this;
    }

    /**
     * Send order notification
     * Notification text fetch from Email Template edited by Admin
     * Email Template Keywords
     * {FirstName} {LastName} {AddressLine1} {AddressLine2}
     * {Email} {Invoice} {Phone} {City} {State} {Zipcode} {Country}
     */
    public function sendOrderMail($orderid=NULL,$status=self::STATUS_PAID)
    {
        $emailnotification = App::Helper('Config')->siteInfo('appstoresettings_emailnotification');

        if($emailnotification=='No'){
            return false;
        }

        if(!isset($orderid)) $orderid = $this->getOrderId();

        $orderData = App::Model('Order')->findById($orderid);
        $shippingaddress = unserialize($orderData['shippingaddress']);

        $params = Array(
            "FirstName" => $shippingaddress['fname'],
            "LastName" => $shippingaddress['lname'],
            "AddressLine1" => $shippingaddress['address_line_1'],
            "AddressLine2" => $shippingaddress['address_line_2'],
            "Email" => $shippingaddress['email'],
            "Invoice" => $this->getInvoice($orderid),
            "Phone" => "",
            "City" => $shippingaddress['city'],
            "State" => $shippingaddress['state'],
            "Zipcode" => $shippingaddress['zipcode'],
            "Country" => App::Helper('Utility')->CountryCodeToName($shippingaddress['country'])
        );

        if($status==self::STATUS_PAID)
        {
            App::Helper('EmailTemplate')
                ->setParameters($params)
                ->prepare('StorePaymentSuccessAdmin',true);

            App::Helper('EmailTemplate')
                ->setParameters($params)
                ->setTo(
                    Array(
                        "{$shippingaddress['email']}",
                        "{$shippingaddress['fname']} {$shippingaddress['lname']}"))
                ->prepare('StorePaymentSuccessCustomer',true);
        }
        else
        {
            App::Helper('EmailTemplate')
                ->setParameters($params)
                ->prepare('StorePaymentFailedAdmin',true);

            App::Helper('EmailTemplate')
                ->setParameters($params)
                ->setTo(
                    Array(
                        "{$shippingaddress['email']}",
                        "{$shippingaddress['fname']} {$shippingaddress['lname']}"))
                ->prepare('StorePaymentFailedCustomer',true);
        }
    }

    /**
     * Do more validation as per
     * Need
     */
    public function orderValidation()
    {
        if(!$this->isToCheckout())
        {
            echo App::Load("Module/Cryptography")->jsonEncode(array("_status" =>"Redirect","_location"=>App::Helper('Config')->baseUrl("/")));
            exit;
        }

        $this->verifyAddress()->verifyAddress('Shipping');

        return $this;
    }

    public function verifyAddress($type="Billing")
    {
        $address = ($type=="Billing")
            ? $this->getBillingAddress()
            : $this->getShippingAddress();

        if(!App::Helper('Validation')->notEmpty($address['fname'])){
            throw new AppException($this->__("Please enter {$type} First Name"));
        }
        else if(!App::Helper('Validation')->notEmpty($address['lname'])){
            throw new AppException($this->__("Please enter {$type} Last Name"));
        }
        else if(!App::Helper('Validation')->notEmpty($address['address_line_1'])){
            throw new AppException($this->__("Please enter {$type} address line 1"));
        }
        else if(!App::Helper('Validation')->notEmpty($address['city'])){
            throw new AppException($this->__("Please enter {$type} valid city"));
        }
        else if(!App::Helper('Validation')->notEmpty($address['state'])){
            throw new AppException($this->__("Please enter {$type} valid state"));
        }
        else if(!App::Helper('Validation')->email($address['email'])){
            throw new AppException($this->__("Please enter {$type} valid email address"));
        }
        else if(!App::Helper('Validation')->notEmpty($address['country'])){
            throw new AppException($this->__("Please enter {$type} valid select country"));
        }

        return $this;
    }

    public function organiseResource()
    {
        $data = $this->getCheckoutPostData();
        $data['Checkout']['shiptobillingaddress'] = isset($data['Checkout']['shiptobillingaddress']) ? "Yes":"No";
        if($data['Checkout']['shiptobillingaddress'] == "Yes"){
            $data['Shipping'] = $data['Billing'];
        }

        $this->setShipToBillingAddress($data['Checkout']['shiptobillingaddress']);
        $this->setShippingAddress($data['Shipping']);
        $this->setBillingAddress($data['Billing']);
        if(!isset($data['Payment']['method'])){
            throw new AppException($this->__('Please select a payment method'));
        }
        $this->setPaymentMethod($data['Payment']['method']);
        $this->setPaymentData(isset($data['Payment'][$data['Payment']['method']]) ? $data['Payment'][$data['Payment']['method']] : Array());
        return $this;
    }

    public function StartCheckoutProcess()
    {
             // Move first Instance
             // of Quote in Data base
        $this->moveOrderInstanceToDB()
             // Move/Update Items
             // database
             ->moveItemsToDB()
             // Set Shipping address, Paymants method
             // by maginc methods and the more full
             // Order to database
             //---------------------------------------+
             ->completeOrderUpdate();


        if($this->enablepaymentprocessor){
            // Instantiate payment process class and execute.
            // We always expect a class with the pattern of
            // "Pgateway_PaymentMethod" For example "Pgateway_Paypal".
            // This class will auto load from "development/helper/pgateway".
            // Each payment class must have a method place() that will
            // execute form this point and do other task as per need
            // and for any invalid operation throw a exception that will
            // will catch from base checkout call try block in completeCheckoutAction()
            // -----------------------------------------------------------------------+
            App::Component('appStore')
                ->Helper("Pgateway_common")
                ->getObject($this->getPaymentMethod())
                ->setPaymentData($this->getPaymentData())
                ->setAmount($this->totalCost())
                ->setOrderId($this->getOrderId())
                ->setBillingAddress($this->getBillingAddress())
                ->place();
        }
        return $this;
    }
}